package sbpme.designer.parts;

import java.util.List;

import org.eclipse.draw2d.AbstractConnectionAnchor;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.tools.DirectEditManager;

import sbpme.designer.model.Activity;
import sbpme.designer.policy.ActivityComponentEditPolicy;
import sbpme.designer.policy.ActivityDirectEditPolicy;
import sbpme.designer.policy.ActivityGraphicalNodeEditPolicy;

public abstract class ActivityPart extends AbstractPart implements NodeEditPart {

	protected DirectEditManager manager;

	protected void createEditPolicies() {
		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new ActivityGraphicalNodeEditPolicy());
		installEditPolicy(EditPolicy.COMPONENT_ROLE, new ActivityComponentEditPolicy());
		installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new ActivityDirectEditPolicy());
	}

	public void deactivate() {
		super.deactivate();
		// getActivity().removePropertyChangeListener(this);
	}

	public void refreshVisuals() {
		// ((Figure)getFigure()).setName( ((Activity)getModel()).getName() );
		Rectangle constraint = null;
		if (getActivity().getConstraint() != null) {
			constraint = new Rectangle(getActivity().getConstraint());
		} else {
			constraint = new Rectangle(new Point(0, 0), new Dimension(-1, -1));
		}
		Dimension initialSize = new Dimension(30, 50);// getActivity().getInitialSize();
		Dimension preferredSize = getFigure().getPreferredSize();
		if (constraint.width == -1 && initialSize.width > preferredSize.width) {
			constraint.width = initialSize.width;
		}
		if (constraint.height == -1 && initialSize.height > preferredSize.height) {
			constraint.height = initialSize.height;
		}
		((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), constraint);
	}

	protected Activity getActivity() {
		return (Activity) getModel();
	}

	protected List getModelSourceConnections() {
		return getActivity().getSourceTransitions();
	}

	protected List getModelTargetConnections() {
		return getActivity().getTargetTransitions();
	}

	protected int getAnchorOffset() {
		return getFigure().getPreferredSize().width / 2;
	}

	public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
		return new BottomAnchor(getFigure(), getAnchorOffset());
	}

	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		return new BottomAnchor(getFigure(), getAnchorOffset());
	}

	public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
		return new TopAnchor(getFigure(), getAnchorOffset());
	}

	public ConnectionAnchor getTargetConnectionAnchor(Request request) {
		return new TopAnchor(getFigure(), getAnchorOffset());
	}

	protected void performDirectEdit() {
	}

	public void performRequest(Request request) {
		if (request.getType() == RequestConstants.REQ_DIRECT_EDIT)
			performDirectEdit();
	}

	protected void setFigure(IFigure figure) {
		figure.getBounds().setSize(0, 0);
		super.setFigure(figure);
	}

	public String toString() {
		return getModel().toString();
	}

	class BottomAnchor extends AbstractConnectionAnchor {

		private int offset;

		BottomAnchor(IFigure source, int offset) {
			super(source);
			this.offset = offset;
		}

		public Point getLocation(Point reference) {
			Rectangle r = getOwner().getBounds().getCopy();
			getOwner().translateToAbsolute(r);
			int off = offset;
			if (off == -1)
				off = r.width / 2;
			if (r.contains(reference) || r.bottom() > reference.y)
				return r.getTopLeft().translate(off, 0);
			else
				return r.getBottomLeft().translate(off, -1);
		}

	}

	class TopAnchor extends AbstractConnectionAnchor {

		private int offset;

		TopAnchor(IFigure source, int offset) {
			super(source);
			this.offset = offset;
		}

		public Point getLocation(Point reference) {
			Rectangle r = getOwner().getBounds().getCopy();
			getOwner().translateToAbsolute(r);
			int off = offset;
			if (off == -1)
				off = r.width / 2;
			if (r.contains(reference) || r.y < reference.y)
				return r.getBottomLeft().translate(off, -1);
			else
				return r.getTopLeft().translate(off, 0);
		}

	}
}
